JBoss Community Archive (Read Only)

PicketBox

Time Password

Introduction

This section describes how to authenticate users using a username, password and a Time-Based One-Time Password (TOTP) as credentials.

This authentication type is provided by the org.picketbox.core.authentication.impl.OTPAuthenticationMechanism.

You do not need any specific configuration to use this mechanism, it is already configured when you start PicketBox.

Supported Credentials

This mechanism supports the following credential:

  • org.picketbox.core.authentication.credential.OTPCredential

The code bellow demonstrates how to create this credential type.

String token = generateOTP();
String userName = "admin";
String password = "admin";
        
UserCredential credential = new OTPCredential(userName, password, token);

How TOTP tokens are generated ?

Using the API

To generate TOTP tokens programatically you use the org.picketbox.core.util.TimeBasedOTP utility class.

Generating TOTP tokens programatically
String secretKey = "change_me";
String totp = TimeBasedOTP.generateTOTP(secretKey, NUMBER_OF_DIGITS);

// now you can authenticate the user using the generated token

Beside the secret key, you must specify the token length (see the NUMBER_OF_DIGITS above). Usually, you will use 6 digits.

Using the Google Authenticator

If you want to generate tokens on your phone you can use the Google Authenticator. Check the documentation for details about how installing and configuring your tokens.

The only thing you should be aware is about time syncronization between your phone and the server where you application is running. To help you sync your devices, you can use the TOTP Debugger. This tools helps you to find problems related with time syncronization between your phone, the google servers and the server where your application is running.

How TOTP tokens are validated ?

The OTP authentication mechanism must know where the secret key is stored to validate tokens. That said, before authenticating an user you need to provide his secret key and store it as an attribute.

Storing the user's secret key
/**
  * <p>Generates a secret key for an user if none is defined. The secret key should be stored as an attribute to allow the authentication mechanism retrieve it and perform the token validation.</p>
  */
private String generateOTP(User user) throws GeneralSecurityException {
    String secretKey = user.getAttribute("serial");

    if (secretKey == null) {
        //Generate a random number and use as the secret key
        secretKey = UUID.randomUUID().toString();

        secretKey = secretKey.replace('-', 'c');

        //Just pick the first 10 characters
        secretKey = secretKey.substring(0, 10);

        user.setAttribute("serial", secretKey);
     }

     return TimeBasedOTP.generateTOTP(secretKey, NUMBER_OF_DIGITS);
}    

The name of the attribute where the secret key is stored must be "serial". This name will be used by the OTP authentication mechanism to locate the attribute and get the secret key to perform the authentication.

Another important point regarding validation is how a specific token is considered valid given the time interval in which it was generated. During the validation the following rules are applied:

  1. Check if the provided token matches a token generated by the server using the current interval or time. If so, the token is considered valid.

  2. Check if the provided token matches a token generated considering the previous interval or time.

  3. Check if the provided token matches a token generated considering the next interval or time.

The interval has a important hole when dealing with TOTP tokens. The time of the interval impacts directly how the token is generated and validated. That said, PicketBox uses by default an interval of 30 seconds. This is the window to consider if a token is valid or not.

Example

One-Time Password Authentication
    
    /**
     * <p>Token number of digits.</p>
     */
    private static final int NUMBER_OF_DIGITS = 6;

    /**
     * <p>
     * Tests if the authentication performs successfully when provided a valid {@link OTPCredential}.
     * </p>
     * @throws Exception
     *
     * @throws AuthenticationException
     */
    @Test
    public void testSuccessfulAuthentication() throws Exception {
        PicketBoxManager picketBoxManager = createManager();

        // gets the identity manager instance
        IdentityManager identityManager = picketBoxManager.getIdentityManager();

        // load the user from the identity store
        User adminUser = identityManager.getUser("admin");

        // creates new authenticating context
        UserContext authenticatingUser = new UserContext();

        String userName = "admin";
        String password = "admin";
                // generates the TOTP token
        String totp = generateOTP(adminUser);

        // creates the OTP credential
        UserCredential credential = new OTPCredential(userName, password, totp);

        // populates the authenticating context
        authenticatingUser.setCredential(credential);

        // let's authenticate the user
        UserContext authenticatedUser = picketBoxManager.authenticate(authenticatingUser);

        assertNotNull(authenticatedUser);
        assertTrue(authenticatedUser.isAuthenticated());
     }

     /**
      * <p>Generates a secret key for an user if none is defined. The secret key should be stored as an attribute to allow the authentication mechanism retrieve it and perform the token validation.</p>
      */
     private String generateOTP(User user) throws GeneralSecurityException {
        String secretKey = user.getAttribute("serial");
        
        if (secretKey == null) {
            //Generate a random number and use as the secret key
            secretKey = UUID.randomUUID().toString();
            
            secretKey = secretKey.replace('-', 'c');
            
            //Just pick the first 10 characters
            secretKey = secretKey.substring(0, 10);
                       
            user.setAttribute("serial", secretKey);
        }
        
        return TimeBasedOTP.generateTOTP(secretKey, NUMBER_OF_DIGITS);
    }    
JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-11 12:16:22 UTC, last content change 2012-11-08 14:18:58 UTC.